Injection Attacks = Child’s Play

Injection based attacks have been the number one security risk to Web-apps since 2010. Why is injection at the top? For one, Hackers discover vulnerable sites with little effort. Tools like Havij and Shodan make injection attacks child’s play. The potential impact from injection-based attacks, especially SQL injection, is severe. SQL injection vulnerabilities allow hackers to circumvent security controls and run arbitrary scripts against the database. These scripts might steal data, destroy data, create a backdoor or all the above. Despite the awareness of injection risks, organizations have trouble eliminating the threat. The news article featured in the GIF below were all written in the last two years. They are a few examples of SQL injection that I found interesting.

Large organizations like Cisco, Instagram, and Texas.Gov discovered injection vulnerabilities since 2018. MySQL and PostgreSQL write source code for database systems, and even they are not immune.

Breaking Down a Shiny App

I built a simple shiny app to illustrate how injection works. The app takes an email address and job title as inputs and saves them to a SQL Server database. Users can also update and delete existing records. The app persists user input in one table named dbo.Persons. The following SQL creates dbo.Persons and then inserts one row. The last statement selects all the rows.

1 records
email jobtitle
Analyst

The shiny UI controls provide input to the following queries. R combines the user input and query code.

SELECT, UPDATE, DELETE, and INSERT are the fundamental operations of data modification language (DML). My sample app only executes DML code. The other types of query code are data control language (DCL) and data definition language (DDL). I have not seen many apps use DCL and DDL, but there’re times when it’s useful. The CREATE TABLE query above is an example of DDL. The code below concatenates the user input with query code and executes the statement.

The code is vulnerable to SQL injection. Nothing is stopping a user from passing a SQL script to either one of the inputs. The GIF below first shows how a user a suppose to interact with the app. Then it shows how a hacker can pass a malicious script through the email input field.

The string executed against the database is two separate SQL commands. The second command truncates the Persons table. In a real-world production system, this might be data loss or application downtime.

## [1] "Insert into dbo.Persons values (''','') TRUNCATE TABLE dbo.Persons --','Analyst')"

Defending Against Injection

Paramertization and String Escaping

The app mixes trusted data with untrusted data. Trusted data is the query code, and untrusted data is user input. If untrusted data mixes with trusted data, then query code becomes changeable at run time. I can start to separate the trusted and untrusted data through parameterized queries. Instead of passing the user input variables to the query string, I store them in parameters. Then I reference the parameters instead of the user variables.

The sqlInterpolate function helps isolate the user input from the query string. Also, sqlinterpolate escapes single tick marks making it difficult to execute ad-hoc scripts. The injection attack fails this time because the code handles input as one continuous string.

Whitelist input

The app should only allow valid characters as input. If a user enters an email with spaces, then the app should reject it. I implemented an email whitelist by comparing the input with a Regex pattern.

Developers should whitelist with caution. Using a restrictive character set could block legitimate input. The Regex pattern above blocks email addressed with a single quote. Are quotes possible in emails? If they aren’t allowed will that change in the future? It’s possible. A whitelist requires a balance between security and usability.

Server Side Defense

The database user account should have minimal permissions. I would not have been able to truncate the table in the example above had I only had permission to SELECT and INSERT. Interfaces simplify permissions. Instead of granting permissions on tables I can grant permissions on the interface. Stored procedures make great interfaces. Developers can grant permissions on stored procedures without granting access to tables. Thus DB all interactions occur in the manner defined by the stored procedure.

I can wrap the INSERT statement into a stored procedure. The shinybuilder_app user cannot run an INSERT statement outside of the stored procedure.

Now the app calls the stored procedure instead of ad-hoc SQL.

Other defense layers

  • A few lines of defense exist outside of the app and database server. An intrusion detection system (IDS) uses signatures to detect potential attacks. Some IDS also provide real-time alerting features.

  • Vendor provided patches often contain security fixes. System admins or developers should apply security fixes as soon as possible.

Defense in Depth

Even big firms struggle to manage injection risks, and no code is 100% secure. However, parametrization and whitelists are good first lines of defense.